#include "botwtui.h"

#include "bot.h"
#include <Wt/WEnvironment>
#include <Wt/WServer>
#include "globalargs.h"

/// Extra globals, \todo put them somewhere away
static std::vector<BotWtUI*>    _currentSessions;

void BotWtUI::SLOT_WriteUIString(QString message)
{
    BotUI::GetInstance()._hiddenLogText += message;
    _logTextArea->setText(WString(BotUI::GetInstance()._hiddenLogText.toStdWString()));
    Q_EMIT SIGNAL_WriteConsoleUIString(message);
    SLOT_UpdateFromServer();
}
void BotWtUI::SLOT_WriteUIStringFromConsole(QString message)
{
    /// \todo
}

/// see <a href="http://www.webtoolkit.eu/wt/doc/reference/html/classWt_1_1WApplication.html">void Wt::WApplication::enableUpdates	(	bool 	enabled = true	)</a>.
void BotWtUI::SLOT_UpdateFromServer()
{
    for(auto i: _currentSessions)
    {
        if(i != this)
        {
            // Grab the application lock. It is a scoped lock.
            Wt::WApplication::UpdateLock lock(i);
            if (lock)
            {
                // We now have exclusive access to the application:
                // we can safely modify the widget tree for example.
                i->_logTextArea->setText(WString(BotUI::GetInstance()._hiddenLogText.toStdWString()));

                // Push the changes to the browser
                i->triggerUpdate();
            }
            //WServer::instance()->post(i->sessionId(), &i->SLOT_WriteUIString(""));
        }
    }
}

void BotWtUI::_UICommandExecutor()
{
    SLOT_WriteUIString("[" + QString(WApplication::environment().clientAddress().c_str()) + "]:");

    SLOT_WriteUIString(/*UI_STR_TITLE_LINE + */ QString(_commandEdit->text().toUTF8().data()) + "\r\n");
    lastCommand = QString(_commandEdit->text().toUTF8().data());
    _commandEdit->setText("");
    if(!lastCommand.compare(UI_STR_COMMAND_EXIT))
    {
        /// \todo
    }
    else if(!lastCommand.compare(UI_STR_COMMAND_INFO))
        SLOT_WriteUIString( QString(UI_STR_TITLE_LINE) + UI_STR_MESSAGE_INFO );
    else if(!lastCommand.compare(UI_STR_COMMAND_REGISTER))
        Q_EMIT SIGNAL_RegisterAtEnvironment();
    else if(!lastCommand.compare(UI_STR_COMMAND_CLIENTS))
        Q_EMIT SIGNAL_ShowClients();
    else if(!lastCommand.compare(UI_STR_COMMAND_OCLPLATFORMS))
        Q_EMIT SIGNAL_ShowOCLPlatforms();
    else if(!lastCommand.compare(UI_STR_COMMAND_OCLDEVICES))
        Q_EMIT SIGNAL_ShowOCLDevices();
}

BotWtUI::BotWtUI(const WEnvironment& env): WApplication(env)
{
    this->enableUpdates(true);

    // init web-console Ui redirections
    //BotUI::GetInstance().connect(&BotUI::GetInstance(), SIGNAL(SIGNAL_WriteWebUIString(QString)),
    //    this,SLOT(SLOT_WriteUIStringFromConsole(QString)));
    this->connect(&BotUI::GetInstance(), SIGNAL(SIGNAL_UpdateWebUI()),
        this,SLOT(SLOT_UpdateFromConsole()));
    this->connect(this, SIGNAL(SIGNAL_WriteConsoleUIString(QString)),
        &BotUI::GetInstance(),SLOT(SLOT_WriteUIStringFromWeb(QString)));

    this->connect(this, SIGNAL(SIGNAL_RegisterAtEnvironment()),
        &BotUI::GetInstance(),SIGNAL(SIGNAL_RegisterAtEnvironment()));
    this->connect(this, SIGNAL(SIGNAL_FatalError(QString)),
        &BotUI::GetInstance(),SIGNAL(SIGNAL_FatalError(QString)));
    this->connect(this, SIGNAL(SIGNAL_ShowClients()),
        &BotUI::GetInstance(),SIGNAL(SIGNAL_ShowClients()));
    this->connect(this, SIGNAL(SIGNAL_ShowOCLDevices()),
        &BotUI::GetInstance(),SIGNAL(SIGNAL_ShowOCLDevices()));
    this->connect(this, SIGNAL(SIGNAL_ShowOCLPlatforms()),
        &BotUI::GetInstance(),SIGNAL(SIGNAL_ShowOCLPlatforms()));

    setTitle("CBN Web Console");                                // application title

    _myLayout = new WVBoxLayout(root());
    root()->setLayout(_myLayout);

    _GLWidget = new BotWtGLWidget(root());                      // BotWtGLWidget
    _GLWidget->setWidth(640);
    _GLWidget->setHeight(360);
    _myLayout->addWidget(_GLWidget);

    _logTextArea = new WTextArea(root());                       // text area
    _logTextArea->setReadOnly(true);
    //_logTextArea->setSelectable(false);
    _logTextArea->setMaximumSize(WLength::Auto, WLength::Auto);
    _logTextArea->setMinimumSize(WLength::Auto, WLength::Auto);
    _logTextArea->setText(WString(BotUI::GetInstance()._hiddenLogText.toStdWString()));
    _myLayout->addWidget(_logTextArea);

    _commandEdit = new WLineEdit(root());                        // allow text input
    _commandEdit->setMaximumSize(WLength::Auto, 25);
    _commandEdit->setMinimumSize(WLength::Auto, 25);
    _myLayout->addWidget(_commandEdit,0,Wt::AlignBottom );
    _commandEdit->setFocus();                                    // give focus

    _commandEdit->enterPressed().connect
        (boost::bind(&BotWtUI::_UICommandExecutor, this));
}

BotWtUI::~BotWtUI()
{
    delete _logTextArea;
    delete _GLWidget;
    delete _commandEdit;
    delete _myLayout;

    /// \todo save the reference for direct erasing
    auto _myAppRef = std::find(_currentSessions.begin(),_currentSessions.end(),this);
    _currentSessions.erase(_myAppRef);
}

WApplication* WebServerRunner::createApplication(const WEnvironment& env)
{
    BotWtUI *_myApp = new BotWtUI(env);
    _currentSessions.push_back(_myApp);
    return _myApp;
}

void BotWtUI::updateAllUserSessions()
{
    for(auto i: _currentSessions)
    {
        Wt::WApplication::UpdateLock lock(i);
        i->_logTextArea->setText(WString(BotUI::GetInstance()._hiddenLogText.toStdWString()));
        i->triggerUpdate();
    }
}

void WebServerRunner::run()
{
    try
    {
        /// \todo here is some bug?
        int argc = 7;
        char *argv[] = {"Bot","--docroot",".","--http-address", "0.0.0.0", "--http-port", "80"};
        _myWServer = new WServer(argv[0]);
        _myWServer->setServerConfiguration(argc, argv, WTHTTP_CONFIGURATION);
        _myWServer->addEntryPoint(Wt::Application, &createApplication);
        if (_myWServer->start()) {
            int _sig = WServer::waitForShutdown(argv[0]);
            std::cerr << "Shutdown (signal = " << _sig << ")" << std::endl;
            _myWServer->stop();
            //if (sig == SIGHUP)
            //  WServer::restart(argc, argv, environ);
        }
        delete _myWServer;
    }
    catch (WServer::Exception& e)
    {
        std::cerr << e.what() << "\n";
        return;
    }
    catch (std::exception& e)
    {
        std::cerr << "exception: " << e.what() << "\n";
        return;
    }
}
